package com.runa.monitor.platinterface.netservice.handler;

import com.alibaba.fastjson.JSON;
import com.runa.monitor.platinterface.extend.equ.EquInstructService;
import com.runa.monitor.platinterface.netservice.equipment.NetEqu;
import com.runa.monitor.platinterface.netservice.equipment.furuisi.FuRuiSiClientDriver;
import com.runa.persistence.util.LogUtil;
import com.runa.protocol.analysis.DataAnalysis;
import com.runa.protocol.analysis.ShellBufferAnalysis;
import com.runa.protocol.util.ByteUtil;
import com.runa.rccprotocol.dto.runa.RunaConcenResponseData;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * @author zhuj
 */
public class ProtocolDecoder extends ByteToMessageDecoder {

    private static final Logger logger = LoggerFactory.getLogger(ProtocolDecoder.class);

    private final DataAnalysis analysis;

    ProtocolDecoder(DataAnalysis analysis) {
        this.analysis = analysis;
    }

    private final ThreadLocal<byte[]> bufferLocal = new ThreadLocal<>();

    public String getSerial(ChannelHandlerContext ctx) {
        String id = ctx.channel().id().asLongText();
        Object serial = NetEqu.getSerial(id);
        if (null != serial) {
            return String.valueOf(serial);
        }
        return null;
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        int begin = in.readerIndex();
        int canRead = in.readableBytes();
        if (canRead < 0) {
            return;
        }
        byte[] bs = takeLocalBuffer(canRead);
        in.markReaderIndex();
        in.readBytes(bs, 0, canRead);
        try {
            String serial = getSerial(ctx);
            LogUtil.info(serial, bs, canRead, "收到 {} {} ", ctx.channel().remoteAddress(), ctx.channel().id());
            logger.info("decode: {} {} {} {}", serial, ByteUtil.byteToHexString(bs, 0, canRead), ctx.channel().localAddress(), ctx.channel().remoteAddress());
            EquInstructService.receive(serial, ByteUtil.byteToHexString(bs, 0, canRead));
            int status = analysis.fill(bs, canRead, serial);
            if (status == 0) {
                if (analysis.gain() != null) {
                    out.add(analysis.gain());
                }
            } else if (status < 0) {
                in.resetReaderIndex();
            } else {
                if (analysis.gain() != null) {
                    out.add(analysis.gain());
                }
                in.readerIndex(begin + canRead - status);
            }
        } catch (Exception e) {
            logger.error("ProtocolDecode: ", e);
        } finally {
            //设置过netequ的指令会详细显示（包括心跳），其他注册心跳
//            if (analysis instanceof ShellBufferAnalysis){
            if (analysis.gain() != null && analysis.gain() instanceof RunaConcenResponseData){
                logger.debug("FromData:{}  Serial:{}  Decode:{}  Local:{}", ctx.channel().remoteAddress(), ((ShellBufferAnalysis) analysis).netEquNo, ByteUtil.byteToHexString(bs, 0, canRead), ctx.channel().localAddress());
            }else {
                logger.debug("FromDtuReport:{}  Serial:{}  Decode :{}  Local:{}",ctx.channel().remoteAddress(),NetEqu.getSerial(ctx.channel().id().asLongText()), ByteUtil.byteToHexString(bs, 0, canRead), ctx.channel().localAddress());
            }
        }
    }

    private static final int BufferSize = 2048;

    private byte[] takeLocalBuffer(int read) {
        if (bufferLocal.get() == null) {
            bufferLocal.set(new byte[BufferSize]);
        }
        if (read > BufferSize) {
            bufferLocal.set(new byte[read]);
        }
        return bufferLocal.get();
    }
}
